package org.filecollector.filecontroller.virtualcatalogue;

import junit.framework.TestCase;
import org.apache.commons.lang3.ArrayUtils;
import org.filecollector.filecontroller.virtualcatalogue.virtualfile.VirtualFile;
import org.filecollector.filecontroller.virtualcatalogue.virtualfile.VirtualFileDependencies;
import org.filecollector.filecontroller.virtualcatalogue.virtualfile.VirtualFilesFactory;
import org.junit.Test;

import java.io.*;
import java.util.*;

public class TestVirtualCatalogue{
    private static VirtualCatalogueClass constructTest(String name) {
        return (VirtualCatalogueClass) VirtualCatalogueFactory.constructTest(name);
    }

    private VirtualCatalogueClass hardPut(VirtualCatalogueClass catalogue, VirtualFile vf) {
        catalogue.data.FileMap().put(vf.getId(), vf);
        return catalogue;
    }

    @Test
    public void TestExists() {
        var vc = constructTest("0000000000000000M63");
        hardPut(vc, VirtualFilesFactory.constructTest(vc.data.directory(), 1L));
        TestCase.assertTrue(vc.exists(1L));
        TestCase.assertFalse(vc.exists(0L));
    }

    @Test
    public void TestReadDirectly() {
        var buf = new char[]{'s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g'};
        var vc = constructTest("0000000000000000M63");
        var file = VirtualFilesFactory.constructTest(vc.data.directory(), 1L);
        try(FileWriter writer = new FileWriter(file.getDao().innerFile())) {
            writer.write(buf);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        hardPut(vc, file);
        var ret = vc.readDirectly(1L, buf.length);
        int i = 0;
        for (var c : buf) {
            TestCase.assertEquals(ret.get()[i], c);
            i++;
        }
    }

    @Test
    public void TestGetPath() {
        var vc = constructTest("0000000000000000M63");
        var file = VirtualFilesFactory.constructTest(vc.data.directory(), 1L);
        hardPut(vc, file);
        TestCase.assertEquals(vc.getPath(1L).get(), file.getDao().innerFile().toPath());
    }

    @Test
    public void TestGetCheckSum() {
        var vc = constructTest("0000000000000000M63");
        var file = VirtualFilesFactory.constructTest(vc.data.directory(), 1L);
        hardPut(vc, file);
        TestCase.assertEquals(
                vc.getCheckSum(1L),
                VirtualFileDependencies.getTest().checkSumCounter().apply(null)
        );
    }

    @Test
    public void TestWriteDirectly() {
        var vc = constructTest("0000000000000000M63");
        var vf = VirtualFilesFactory.constructTest(vc.data.directory(), 1L);
        hardPut(vc, vf);
        char[] exp = {'f', 'u', 'c', 'k'};
        char[] ret = new char[exp.length];
        var data = vf.getDao();
        vc.writeDirectly(1L, exp);
        var file = data.innerFile();
        try(FileReader reader = new FileReader(file)) {
            reader.read(ret);
        } catch (Exception e) {
            throw new RuntimeException();
        }
        int i = 0;
        for (var ch : exp) {
            TestCase.assertEquals(ch, ret[i]);
            i++;
        }
        char[] add = {'a', 'd', 'd'};
        char[] exp2 = ArrayUtils.addAll(exp, add);
        char[] ret2 = new char[exp2.length];
        vf.writeDirectly(add, true);
        try(FileReader reader = new FileReader(file)) {
            reader.read(ret2);
        } catch (Exception e) {
            throw new RuntimeException();
        }
        i = 0;
        for (var ch : exp2) {
            TestCase.assertEquals(ch, ret2[i]);
            i++;
        }
    }

    @Test
    public void TestTouch() {
        var vc = constructTest("0000000000000000M63");
        vc.touch(3L);
        TestCase.assertTrue(
                Arrays.stream(
                        Objects.requireNonNull(vc.data.directory().listFiles()))
                        .anyMatch((File f) -> f.getName().equals("3"))
        );
    }

    @Test
    public void TestCheckId() {
        var vc = constructTest("20M4");
        TestCase.assertTrue(vc.checkId(40L));
        TestCase.assertFalse(vc.checkId(5L));
    }
}
